#pragma once

#include "../utils/tokenizer.h"
#include <vector>


#define MAX_PLATFORMS 32    // max. ennyi fajlt tud osszehasonlitani

//
// config
//

// tobb benchmark eredmenyt egy configon "keresztul" hasonlitunk ossze

/*

CConfigFile
{
    CConfigModule "A"
    {
        CONFIGNODE a1
        ...
        CONFIGNODE aN
    }

    ...

    CConfigModule "M"
    {
        CONFIGNODE m1
        ...
        CONFIGNODE MN
    }
}

*/

struct CONFIGNODE
{           
    CChString name;         // pl. "alloc1"
    float weight;           // pl. 0.234    
};


class CConfigModule
{
public:
    bool ReadConfig(CTokenizer *tokens);

    const CChString *GetName() const        { return &m_Name; }
    const CChString *GetLongName() const    { return &m_LongName; }
    float GetWeight() const                 { return m_Weight; }    
    
    const CONFIGNODE *GetNodeByName(const CChString *find) const;
    const std::vector<CONFIGNODE> &GetNodes() const { return m_Nodes; }

private:
    CChString   m_Name;                     // modul neve, pl. "memory"
    CChString   m_LongName;                 // user friendly, pl. "Memory Test"
    float       m_Weight;

    std::vector<CONFIGNODE> m_Nodes;        // pl. "alloc1", "free1", "alloc2"
};


class CConfigFile
{
public:                             
    CConfigFile();
    ~CConfigFile();

    bool Load(const char *TXTfilename);
    void Cleanup();

    const CConfigModule *GetModuleConfigByName(const CChString *find) const;

    static void Merge(CConfigFile *configs[], int count, const char *filename);


private:
    std::vector<CConfigModule*> m_Configs;    

    // masolas tiltasa
private:
   CConfigFile(const CConfigFile &);
   CConfigFile operator=(const CConfigFile &);
};


//
// results (egy benchmark eredmenye, nem egy osszehasonlitase)
//

/*

CResultFile
{
    RESULTFILEINFO

    CResultModule "A"
    {
        RESULTNODE a1
        ...
        RESULTNODE aN
    }

    ...

    CResultModule "M"
    {
        RESULTNODE m1
        ...
        RESULTNODE MN
    }
}

*/

struct RESULTSFILEINFO      // egy benchmark eredmenyet tartalmazo fajlnak (out/akarmi.txt) az elejen van egy kis info a futtato kornyezetrol
{          
    CChString hw;
    CChString os;
    CChString compiler;
    CChString lib;
    CChString comment;
    CChString created;
    CChString display_name;
    CChString gettime_precision;
    int       pb_version;    // ilyen verzioju pbench -el keszult (PBENCH_VERSION)

    RESULTSFILEINFO();
    bool OnReadResult(CTokenizer *tokens);
    void Print(FILE *out) const;
};


struct RESULTNODE
{    
    CChString name;         // pl. "alloc1"
    float result;           // ido
};


class CResultModule
{
public:
    bool ReadResults(CTokenizer *tokens);

    const std::vector<RESULTNODE> *GetNodes() const     { return &m_Nodes; }
    const CChString *GetName() const                    { return &m_ModuleName; }
    
private:
    std::vector<RESULTNODE> m_Nodes;

    CChString m_ModuleName;     // belso nev azonositashoz, pl. "memory"
};


class CResultFile
{
public:
    ~CResultFile();

    bool Load(const char *TXTfilename);
    void Cleanup();

    const CChString *GetDisplayName() const { return &m_Info.display_name; }

    const std::vector<CResultModule*> *GetModules() const { return &m_Modules; }
    const RESULTNODE *GetResult(const CChString *modulename, const CChString *nodename) const;

private:
    std::vector<CResultModule*> m_Modules;
    RESULTSFILEINFO             m_Info;
};


// 
// benchmark output
//


/*

CResultManager
{
    bemenet:    
    CConfigFile                 - SetConfig()
    CResultFile[]               - LoadFile()

    GenerateOutput() utan kimenet:
    
    BENCHMARK_TOTAL
    BENCHMARK_MODULE[modulok_szama]
    BENCHMARK_NODE[nodeok_szama]

    TODO: a kimenetet mashol tarolni?
}


*/

struct BENCHMARK_TOTAL
{    
    std::vector<CChString> filenames;               // az eredmenyek nevei  "Pistike Ubuntu 7.10"
    double maxvalue;                                // values[] maximuma (redundans, a megjelenites konnyebb, ha ki van szamolva)
    double values[MAX_PLATFORMS];                   // arany, 10s/100s = 0.1
    double times[MAX_PLATFORMS];                    // 10s
    double weighted_times[MAX_PLATFORMS];           // 10s * weight
};


struct BENCHMARK_MODULE
{
    CChString name;                                 // "Memoria Teszt"
    int firstnode;                                  // BENCHMARK_NODE -ok kozul az elso, ami a modulhoz tartozik
    int nodecount;                                  // ennyi BENCHMARK_NODE van a modulban (firstnode-tol kezdodoen)
    double maxvalue;                                // values[] maximuma
    double values[MAX_PLATFORMS];                   // 1s/2s = 0.5
    double times[MAX_PLATFORMS];                    // 1s
    double weighted_times[MAX_PLATFORMS];           // 0.5s * weight
};


struct BENCHMARK_NODE
{
    CChString name;                                 // "alloc1024x16"
    double maxvalue;
    double values[MAX_PLATFORMS];                   // referencia / gep[i] aranya
    double times[MAX_PLATFORMS];                    // gep[i] ideje
};


class CResultManager
{
public:
    ~CResultManager();
    void Cleanup();

    bool SetConfig(const char *TXTfilename) { return m_Config.Load(TXTfilename); }
    bool LoadFile(const char *filename);
    bool GenerateOutput(unsigned reference_file);   // referencia fajl indexe (0..m_Files.size()-1)

    // eredmeny lekerdezese
    const BENCHMARK_TOTAL *GetResultTotal() const                   { return &m_TotalOutput; }
    const std::vector<BENCHMARK_MODULE> *GetResultModules() const   { return &m_ModuleOutput; }
    const std::vector<BENCHMARK_NODE> *GetResultNodes() const       { return &m_NodeOutput; }

private:
    // input
    std::vector<CResultFile*>       m_Files;    
    CConfigFile                     m_Config;

    // output
    BENCHMARK_TOTAL                 m_TotalOutput;      // level1 -> platformok
    std::vector<BENCHMARK_MODULE>   m_ModuleOutput;     // level2 -> modulok (memory, cpu, ...)
    std::vector<BENCHMARK_NODE>     m_NodeOutput;       // level3 -> eredmenyek (alloc1, alloc2, ...)
};
